<template>
  <div ref="container" class="lazy-rich-wrapper" :class="{ 'lazy-rich-component': true }">
    <!-- 占位 -->
    <div v-if="!loaded" class="placeholder">
      <div class="loading-content">
        <div class="loading-spinner"></div>
        <span>富文本加载中...</span>
      </div>
    </div>

    <!-- 富文本组件 -->
    <component v-else :is="RichTextEditor" v-model="localValue" v-bind="$attrs" />
  </div>
</template>

<script setup>
import { 
  ref, 
  defineAsyncComponent, 
  onMounted, 
  watch, 
  nextTick, 
  onUnmounted,
  computed
} from 'vue'

const RichTextEditor = defineAsyncComponent({
  loader: () => import('./RichTextEditor.vue'),
  loadingComponent: {
    template: '<div class="editor-loading">编辑器加载中...</div>'
  },
  errorComponent: {
    template: '<div class="editor-error">编辑器加载失败</div>'
  },
  delay: 200,
  timeout: 5000
})

const props = defineProps({
  modelValue: { 
    type: String, 
    default: '' 
  },
  immediate: { 
    type: Boolean, 
    default: false 
  },
  placeholderHeight: {
    type: [Number, String],
    default: 300
  },
  preloadCount: {
    type: Number,
    default: 2
  },
  // 新增：组件标识，用于精准查找
  componentId: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['update:modelValue', 'loaded', 'error'])

const container = ref(null)
const loaded = ref(false)
const isLoading = ref(false)
const localValue = ref(props.modelValue)

const placeholderStyle = computed(() => ({
  height: typeof props.placeholderHeight === 'number' 
    ? `${props.placeholderHeight}px` 
    : props.placeholderHeight
}))

let globalObserver = null

watch(() => props.modelValue, val => {
  localValue.value = val
})

watch(localValue, val => {
  emit('update:modelValue', val)
})

function loadEditor() {
  if (loaded.value || isLoading.value) return
  
  isLoading.value = true
  loaded.value = true
  isLoading.value = false
  emit('loaded')
  
  if (container.value && container.value._lazyInstanceData) {
    container.value._lazyInstanceData.loaded = true
  }
}

// 改进的预加载方法：基于选择器查找
function preloadNextComponents(currentElement, count) {
  if (!currentElement) return

  // 1. 获取所有懒加载富文本组件
  const allLazyComponents = Array.from(document.querySelectorAll('.lazy-rich-component'))
    .filter(comp => comp._lazyInstanceData) // 必须有挂载数据
    .map(comp => {
      const rect = comp.getBoundingClientRect()
      return {
        element: comp,
        y: rect.top + window.scrollY,
        instanceData: comp._lazyInstanceData
      }
    })
    .sort((a, b) => a.y - b.y) // 按纵坐标排序

  // 2. 找到当前组件在整个列表中的位置
  const currentIndex = allLazyComponents.findIndex(comp => comp.element === currentElement)
  if (currentIndex === -1) return

  // 3. 预加载后续 count 个
  let loadedCount = 0
  for (let i = currentIndex + 1; i < allLazyComponents.length && loadedCount < count; i++) {
    const next = allLazyComponents[i]
    if (!next.instanceData.loaded) {
      next.instanceData.loadEditor() // 触发加载
      loadedCount++
    }
  }
}

function initObserver() {
  if (!container.value || loaded.value) return

  if (props.immediate) {
    loadEditor()
    return
  }

  if (!globalObserver) {
    globalObserver = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const instanceData = entry.target._lazyInstanceData
            if (instanceData && !instanceData.loaded) {
              instanceData.loadEditor()
              // 使用改进的预加载方法
              preloadNextComponents(entry.target, props.preloadCount)
              globalObserver.unobserve(entry.target)
            }
          }
        })
      },
      { 
        rootMargin: '300px 0px', // 增大预加载范围
        threshold: 0.01
      }
    )
  }

  container.value._lazyInstanceData = {
    loadEditor,
    loaded: loaded.value,
    element: container.value,
    id: props.componentId || `lazy-${Math.random().toString(36).substr(2, 9)}`
  }
  
  // 添加类名用于选择器查找
  container.value.classList.add('lazy-rich-component')
  
  globalObserver.observe(container.value)
}

let initTimeout = null
function debouncedInit() {
  clearTimeout(initTimeout)
  initTimeout = setTimeout(initObserver, 50)
}

onMounted(async () => {
  await nextTick()
  debouncedInit()
})

onUnmounted(() => {
  if (container.value && globalObserver) {
    globalObserver.unobserve(container.value)
  }
  
  if (container.value) {
    container.value._lazyInstanceData = null
    container.value.classList.remove('lazy-rich-component')
  }
  
  clearTimeout(initTimeout)
})

defineExpose({
  loadEditor,
  loaded: computed(() => loaded.value)
})
</script>

<style scoped>
.lazy-rich-wrapper {
  min-height: v-bind('placeholderStyle.height');
  margin-bottom: 24px;
  position: relative;
}

.placeholder {
  background: linear-gradient(90deg, #f8f9fa 25%, #e9ecef 50%, #f8f9fa 75%);
  background-size: 200% 100%;
  animation: loading 1.8s ease-in-out infinite;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed #dee2e6;
}

.loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  opacity: 0.8;
}

.loading-spinner {
  width: 28px;
  height: 28px;
  border: 3px solid #f1f3f5;
  border-top: 3px solid #4dabf7;
  border-radius: 50%;
  animation: spin 1.2s linear infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.editor-loading {
  padding: 24px;
  text-align: center;
  color: #868e96;
  background: #f8f9fa;
  border-radius: 8px;
  border: 1px solid #e9ecef;
}

.editor-error {
  padding: 24px;
  text-align: center;
  color: #fa5252;
  background: #fff5f5;
  border-radius: 8px;
  border: 1px solid #ffe3e3;
}
</style>